package middleware

import (
	"context"
	"net/http"
	"time"

	"gitee.com/hp-huiw/my-go-core/date"
	libsecurity "gitee.com/hp-huiw/my-go-core/security"
	"gitee.com/hp-huiw/my-go-core/servercode"
	"github.com/gin-gonic/gin"
)

// TimeoutMiddleware returns a middleware that automatically cancels requests
// exceeding the specified timeout and responds with a detailed JSON error.
func TimeoutMiddleware(timeout time.Duration) gin.HandlerFunc {
	return func(c *gin.Context) {
		// Create a context with timeout derived from the request's context
		ctx, cancel := context.WithTimeout(c.Request.Context(), timeout)
		defer cancel()

		// Replace the request context
		c.Request = c.Request.WithContext(ctx)

		done := make(chan struct{}, 1)

		go func() {
			// Proceed to the next handler
			c.Next()
			done <- struct{}{}
		}()

		select {
		case <-ctx.Done():
			// Timeout or client cancellation occurred
			errMsg := "request timed out"

			if ctx.Err() == context.Canceled {
				errMsg = "request canceled by client"
			}

			c.AbortWithStatusJSON(http.StatusGatewayTimeout, libsecurity.HandlerErrorResponse{
				Error:     servercode.ServerCodeCanceled,
				Message:   errMsg,
				Path:      c.FullPath(),
				Status:    http.StatusGatewayTimeout,
				Success:   false,
				Timestamp: date.GetCurrentDate().Unix(),
			})
		case <-done:
			// Handler finished successfully before timeout
		}
	}
}
